import { isObject } from '@/mxp-ui/mxp-tool/utils/verify';
import { useAppStore } from '@/pinia/app';
import { type _Config, getCustomAuthorization, getMethod, getNetworkType, getUrl, getUrlParams } from './util';
import mxpGetSysInfoStore from '@/mxp-ui/mxp-tool/store/mxp-store-sys-info';
import { refreshToken } from './refresh-token';
import { getAppInfo } from '@/config/mp-config';

/** 配置 */
export type Config = _Config;
/** 请求结果 */
export type Response<T = unknown> = {
  code: number;
  msg: string;
  data: T;
};

/** 分页 */
export type Paging<T> = {
  /** 当前页 */
  current: number;
  /** 数据 */
  records: T[];
  /** 每页数量 */
  size: number;
  /** 总条数  */
  total: number;
};

class Request {
  /** 请求任务 */
  public requestTask: UniApp.RequestTask | null = null;

  /** 请求 */
  public async request(config: _Config) {
    try {
      const data: Record<number | string | symbol, unknown> = isObject(config.data) ? JSON.parse(JSON.stringify(config.data)) : {};
      const newConfig: _Config = isObject(config) ? this.requestInterceptor(config) : {};
      newConfig.url = getUrl(newConfig.baseURL, newConfig.url || '');
      newConfig.method = getMethod(newConfig.method);
      newConfig.header = isObject(newConfig.header) ? newConfig.header : {};
      // 这里会把 url 带的参数和 data 带的参数合并
      newConfig.data = { ...data, ...getUrlParams(newConfig.url || '') };
      const res = await this._request(newConfig);
      return Promise.resolve(res);
    } catch (err) {
      return Promise.reject(err);
    }
  }

  /** get请求 */
  public async get(url: string, config?: _Config) {
    try {
      const _config = (isObject(config) ? config : {}) as _Config;
      _config.url = url;
      _config.method = 'GET';
      const res = await this.request(_config);
      return Promise.resolve(res);
    } catch (err) {
      return Promise.reject(err);
    }
  }
  /** post请求 */
  public async post(url: string, data?: _Config['data'], config?: _Config) {
    try {
      const _config = (isObject(config) ? config : {}) as _Config;
      _config.url = url;
      _config.method = 'POST';
      _config.data = data ?? {};
      const res = await this.request(_config);
      return Promise.resolve(res);
    } catch (err) {
      return Promise.reject(err);
    }
  }

  /** 取消请求 */
  public cancel() {
    if (this.requestTask) {
      this.requestTask.abort();
    }
  }

  /** 请求前置拦截器 */
  private requestInterceptor(config: _Config): _Config {
    const sys = mxpGetSysInfoStore().getSysInfo().value;
    const appStore = useAppStore();
    // 请求超时时间
    config.timeout = 30000;
    // 请求基础地址
    config.baseURL = config?.baseURL || import.meta.env.VITE_BASE_URL;
    config.header = config?.header || {};
    // 优先取 header的 Token
    const access_token: string = config.header['Dsbb-Custom-Access-Token']
      ? config.header['Dsbb-Custom-Access-Token']
      : appStore.loginState && appStore.access_token
        ? appStore.access_token
        : undefined;
    config.header['Content-Type'] = config.header['Content-Type'] ?? 'application/json';
    config.header['Dsbb-Custom-Mac'] = config.header['Dsbb-Custom-Mac'] ?? [sys.model, sys.system, sys.platform, sys.uniPlatform].toString();
    config.header['Dsbb-Custom-Timestamp'] = config.header['Dsbb-Custom-Timestamp'] ?? String(new Date().getTime());
    config.header['Dsbb-Custom-Device-Platform'] = config.header['Dsbb-Custom-Device-Platform'] ?? String(sys.platform);
    config.header['Dsbb-Custom-Platform'] = config.header['Dsbb-Custom-Platform'] ?? sys.uniPlatform;
    config.header['Dsbb-Custom-App-Code'] = config.header['Dsbb-Custom-App-Code'] ?? (getAppInfo()?.appCode || '');
    config.header['Dsbb-Custom-Api-Version'] = String(config.header['Dsbb-Custom-Api-Version'] ?? 12);

    // const page = getCurrentPages();
    // config.header['Dsbb-Custom-Page'] = page[page.length - 1]?.route;
    // config.header['Dsbb-Custom-Uid'] = page[page.length - 1]?.route;
    if (appStore.privateKeyStr) {
      config.header['Dsbb-Custom-Authorization'] =
        config.header['Dsbb-Custom-Authorization'] ?? getCustomAuthorization(config, appStore.privateKeyStr, access_token);
    }
    if (access_token) {
      config.header['Dsbb-Custom-Access-Token'] = config.header['Dsbb-Custom-Access-Token'] ?? access_token;
    }
    return config;
  }
  /** 请求后置拦截器 */
  private async responseInterceptor<T = any>(response: UniApp.RequestSuccessCallbackResult, config: _Config): Promise<Response<T>> {
    if (response.data && isObject(response.data)) {
      const appStore = useAppStore();
      const successCode = config.custom?.successCode || 200;
      const codeKey = config.custom?.codeKey || 'code';
      try {
        if ('code' in response.data && response.data[codeKey] === successCode) {
          return Promise.resolve(response.data as Response<T>);
        } else if ('code' in response.data && response.data.code === 40003) {
          if (!appStore.refresh_token) {
            appStore.logOut();
            return Promise.reject({ ...response.data, code: response.data?.code ?? 40003, msg: response.data?.msg || '登录状态错误，BD2002' });
          } else {
            try {
              const res = await refreshToken(appStore);
              config.header!['Dsbb-Custom-Access-Token'] = res;
              return this._request(config) as Promise<Response<T>>;
            } catch (error) {
              appStore.logOut();
              return Promise.reject({ ...response.data, code: response.data?.code ?? 40003, msg: response.data?.msg || '登录状态错误，BD2003' });
            }
          }
        } else if ('code' in response.data && response.data[codeKey] === 40004) {
          appStore.logOut();
          return Promise.reject({ ...response.data, code: response.data[codeKey] ?? 40003, msg: response.data?.msg || '代码错误，BD2004' });
        } else {
          return Promise.reject({ ...response.data, code: response.data[codeKey] ?? -20001, msg: response.data?.msg || '代码错误，BD2005' });
        }
      } catch (e) {
        return Promise.reject({ ...response.data, code: response.data[codeKey] ?? -20002, msg: response.data.msg ?? '请求失败，BD2006' });
      }
    } else {
      response.data = { code: -20003, msg: '数据格式错误，BD2007' };
      return Promise.reject({ code: -1003, msg: '请求失败，数据格式错误' });
    }
  }

  /** 请求 */
  private _request(config: _Config) {
    const that = this;
    return new Promise((resolve, reject) => {
      that.requestTask = uni.request({
        ...config,
        url: config.url || '',
        async success(res) {
          that.requestTask = null;
          try {
            const res2 = await that.responseInterceptor(res, config);
            resolve(res2);
          } catch (err) {
            const newErr = isObject(err) ? err : {};
            reject({ ...newErr, code: newErr.code ?? -20002, msg: newErr.msg ?? '请求失败，BD2008' });
          }
        },
        async fail(err) {
          that.requestTask = null;
          const networkType = await getNetworkType();
          let data = { code: -20003, msg: err.errMsg };
          if (err.errMsg === 'request:fail timeout') {
            data = { code: -20004, msg: '请求超时，BD1009' };
          } else if (networkType === 'none') {
            data = { code: -20005, msg: '暂无网络，BD10010' };
          }
          reject(data);
        },
      });
    });
  }
}
/** 导出实例 */
export default new Request();
